package cn.wolfcode.web.controller;

import cn.wolfcode.domain.Mylog;
import cn.wolfcode.service.IMylogService;
import cn.wolfcode.util.RequiredPermission;
import cn.wolfcode.util.UserContextUtil;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.Date;
import java.util.Map;

@Component //把当前类注入到spring容器中
@Aspect    //把当前类标识为一个切面供容器读取
public class AopConfig {

    @Autowired
    private IMylogService myLogService;

    /**
     * 指定切入点
     * 对贴有自定义注解@RequiredPermission的方法，进行切面
     */
    @Pointcut("@annotation(cn.wolfcode.util.RequiredPermission)")
    private void useMethod() {
    }

    /**
     * 对切入点进行增强
     */
    @Around(value = "useMethod()")
    public Object recordLog(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
        Mylog mylog = new Mylog();
        mylog.setLogUsername(UserContextUtil.getUserContext().getName());

        //String cn.wolfcode.web.controller.EmployeeController.list(Model,EmployeeQueryObject)
        //获得当前方法全限定名 并带参数
        Signature sig = proceedingJoinPoint.getSignature(); //获取连接点的方法签名对象；
        System.out.println(sig);
        MethodSignature msig = null;
        //instanceof 用来测试一个对象是否为一个类的实例
        //MethodSignature是方法签名  方法签名是方法的形式定义
        //下面这个IF也就是判断这个sig是不是方法
        if (!(sig instanceof MethodSignature)) {
            throw new IllegalArgumentException("该注解只能用于方法");
        }
        msig = (MethodSignature) sig;
        //方法名 msig.getName(): list
        System.out.println(msig.getName());
        //参数类型 []数组
        //msig.getParameterTypes() : [interface org.springframework.ui.Model, class cn.wolfcode.qo.EmployeeQueryObject]
        System.out.println(Arrays.toString( msig.getParameterTypes()));
        Object target = proceedingJoinPoint.getTarget(); //获取连接点所在的目标对象；
        //target: cn.wolfcode.web.controller.EmployeeController@1dbd7356
        System.out.println(target);
        //根据这个实例 获取他的字节码对象,再通过字节码对象获取方法对象(需要传入这个方法的名字和参数)
        Method currentMethod = target.getClass().getMethod(msig.getName(), msig.getParameterTypes());

        //获取这个方法的注解 并获取这个注解的name值与expression值,并存入对象
        mylog.setModule(currentMethod.getAnnotation(RequiredPermission.class).name());
        mylog.setExpression(currentMethod.getAnnotation(RequiredPermission.class).expression());
        //获得IP地址要通过request(请求头) 所以要取出request对象
        ServletRequestAttributes attrs =
                (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        HttpServletRequest request = attrs.getRequest();
        //获取IP地址
        String ip = request.getHeader("x-forwarded-for");
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("Proxy-Client-IP");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("WL-Proxy-Client-IP");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("HTTP_CLIENT_IP");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("HTTP_X_FORWARDED_FOR");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getRemoteAddr();
        }
        //把ip设置进对象中
        mylog.setIp(ip);
        //设置请求参数
        Map<String,String[]> map = request.getParameterMap();
        String str = "{" ;
        if (map != null){
            for (Map.Entry<String, String[]> entry : map.entrySet()) {
                str += entry.getKey() + ":"+Arrays.toString(entry.getValue())+";";
            }
            str += "}";
            mylog.setParameter(str);
        }
        //操作时间
        Date startDate = new Date();
        mylog.setOperateTime(startDate);

        //执行处理方法（执行控制器中的方法）

        Object result = null ;
        try {
            result = proceedingJoinPoint.proceed();
            //执行controller后
            Date endDate = new Date();
            //设置时长
            mylog.setDuration((endDate.getTime() - startDate.getTime()));
            //设置状态
            mylog.setStatus(true);
            myLogService.save(mylog);
        } catch (Throwable throwable) {
            //执行controller后
            Date endDate = new Date();
            //设置时长
            mylog.setDuration((endDate.getTime() - startDate.getTime()));
            //设置状态
            mylog.setStatus(false);
            mylog.setDetails(throwable.getMessage());
            myLogService.save(mylog);
            throw  throwable;
        }
        //result是方法的返回值，直接return回去就会返回给springmvc处理
        return result;
    }


}